import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import axios from 'axios'
import { useTokenStore } from '@/stores/token'
import router from '@/router'
import { logoutResult } from '@/util/session'

export interface Result<T = any> {
  code: number
  msg: string
  data: T
}

class request {
  private instance: AxiosInstance

  constructor(config: AxiosRequestConfig) {
    this.instance = axios.create(config)
    this.interceptors() // 先初始化拦截器
  }

  private interceptors() {
    this.instance.interceptors.request.use(
      (config) => {
        const token = useTokenStore().getToken() // 在拦截器内获取token
        if (token) {
          config.headers = {
            ...config.headers,
            Token: token,
          }
        }
        return config
      },
      (error) => {
        error.data = {}
        error.data.msg = '服务器异常'
        return Promise.reject(error)
      },
    )
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => response.data,
      (error) => {
        if (error?.response?.status === 401) {
          logoutResult()
          router.replace('/login')
        }
        return Promise.reject(error) // 会在catch中捕获到error
        // return error
      },
    )
  }
  // 封装请求
  service<T>(config: AxiosRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          resolve(res)
        })
        .catch((error) => {
          reject(error)
          return error
        })
    })
  }
  // 封装get请求
  get<T = Result>(config: AxiosRequestConfig): Promise<T> {
    return this.service<T>({ ...config, method: 'GET' })
  }
  // 封装post请求
  post<T = Result>(config: AxiosRequestConfig): Promise<T> {
    return this.service<T>({ ...config, method: 'POST' })
  }
  // delete请求
  delete<T = Result>(config: AxiosRequestConfig): Promise<T> {
    return this.service<T>({ ...config, method: 'DELETE' })
  }
  // put请求
  put<T = Result>(config: AxiosRequestConfig): Promise<T> {
    return this.service<T>({ ...config, method: 'PUT' })
  }
}

export default request
